package com.brave.mvvm.helper.core.net

import android.content.Context
import com.brave.mvvm.helper.core.PApp
import com.brave.mvvm.helper.core.PAppConfig
import com.brave.mvvm.mvvmhelper.http.LoggingInterceptor
import com.brave.mvvm.mvvmhelper.http.cookie.CookieJarImpl
import com.brave.mvvm.mvvmhelper.http.cookie.store.PersistentCookieStore
import com.lzy.okgo.https.HttpsUtils
import okhttp3.Cache
import okhttp3.ConnectionPool
import okhttp3.OkHttpClient
import retrofit2.Retrofit
import retrofit2.adapter.rxjava3.RxJava3CallAdapterFactory
import retrofit2.converter.gson.GsonConverterFactory
import java.io.File
import java.util.concurrent.TimeUnit

/**
 * ***author***     ：BraveTou
 *
 * ***blog***       ：https://blog.csdn.net/bravetou
 *
 * ***time***       ：2020/12/10 14:53
 *
 * ***desc***       ：Retrofit 帮助类
 */
class RetrofitUtils private constructor() {
    private val context: Context = PApp.instance
    private val httpCacheDirectory: File
    private val cache: Cache
    private val mClient: OkHttpClient
    private val mRetrofit: Retrofit

    companion object {
        val instance: RetrofitUtils
            get() = LazyHolder.INSTANCE
    }

    private object LazyHolder {
        val INSTANCE = RetrofitUtils()
    }

    init {
        httpCacheDirectory = File(context.cacheDir, "PrivacyToMonitorCache")
        cache = Cache(httpCacheDirectory, PAppConfig.CACHE_TIMEOUT)
        val sslParams: HttpsUtils.SSLParams = HttpsUtils.getSslSocketFactory()
        mClient = OkHttpClient.Builder()
            .cache(cache)
            .cookieJar(CookieJarImpl(PersistentCookieStore(context)))
            .sslSocketFactory(sslParams.sSLSocketFactory, sslParams.trustManager)
            .connectTimeout(PAppConfig.CONNECTION_TIMEOUT, TimeUnit.SECONDS)
            .readTimeout(PAppConfig.READ_TIMEOUT, TimeUnit.SECONDS)
            .writeTimeout(PAppConfig.WRITE_TIMEOUT, TimeUnit.SECONDS)
            .connectionPool(ConnectionPool(8, 15, TimeUnit.SECONDS))
            .addInterceptor(
                LoggingInterceptor.Builder()
                    .addHeader(
                        "Sign",
                        "cc8a4d26540ef0a6f2181391797ffe96f5029cd59b9f5863013e4a9082a600ac6e71592376f69aa395103688f963ea7f12bcaf325cf64a4b65b6f5e3d8681a6a"
                    )
                    .addHeader("jid", "0")
                    .addHeader("ApiAuth", "")
                    .addHeader("VersionName", "1.1.9")
                    .addHeader("VersionCode", "119")
                    .addHeader("DeviceId", "23369f4e8b674658")
                    .addHeader("LoginDevice", "Android HUAWEI LRA-AL00 10")
                    .addRedirect("develop", "http://dev.api.infocq.com")
                    .loggable(true)
                    .baseUrl(PAppConfig.BASE_URL)
                    .build()
            )
            .build()
        mRetrofit = getRetrofit(PAppConfig.BASE_URL)
    }

    /**
     * 获取 Retrofit
     */
    fun getRetrofit(): Retrofit {
        return mRetrofit
    }

    /**
     * 获取 Retrofit
     */
    fun getRetrofit(baseUrl: String): Retrofit {
        return Retrofit.Builder()
            .baseUrl(baseUrl)
            .addConverterFactory(GsonConverterFactory.create())
            .addCallAdapterFactory(RxJava3CallAdapterFactory.create())
            .client(mClient)
            .build()
    }

    /**
     * Create an implementation of the API endpoints defined by the `service` interface. <br></br>
     *
     * @ [retrofit2.http.GET] 表明这是get请求 <br></br>
     * @ [retrofit2.http.POST] 表明这是post请求 <br></br>
     * @ [retrofit2.http.PUT] 表明这是put请求 <br></br>
     * @ [retrofit2.http.DELETE] 表明这是delete请求 <br></br>
     * @ [retrofit2.http.PATCH] 表明这是一个patch请求，该请求是对put请求的补充，用于更新局部资源 <br></br>
     * @ [retrofit2.http.HEAD] 表明这是一个head请求 <br></br>
     * @ [retrofit2.http.OPTIONS] 表明这是一个option请求 <br></br>
     * @ [retrofit2.http.HTTP] 通用注解, 可以替换以上所有的注解，其拥有三个属性：method，path，hasBody <br></br>
     * @ [retrofit2.http.Headers] 用于添加固定请求头，可以同时添加多个。通过该注解添加的请求头不会相互覆盖，而是共同存在 <br></br>
     * @ [retrofit2.http.Header] 作为方法的参数传入，用于添加不固定值的Header，该注解会更新已有的请求头 <br></br>
     * @ [retrofit2.http.Body] 多用于post请求发送非表单数据, 比如想要以post方式传递json格式数据 <br></br>
     * @ [retrofit2.http.Field] 多用于post请求中表单字段, Filed和FieldMap需要FormUrlEncoded结合使用 <br></br>
     * @ [retrofit2.http.FieldMap] 和@Filed作用一致，用于不确定表单参数 <br></br>
     * @ [retrofit2.http.Part] 用于表单字段, Part和PartMap与Multipart注解结合使用, 适合文件上传的情况 <br></br>
     * @ [retrofit2.http.PartMap] 用于表单字段, 默认接受的类型是Map<String></String>,REquestBody>，可用于实现多文件上传 <br></br>
     *
     *
     * Part标志上文的内容可以是富媒体形势，比如上传一张图片，上传一段音乐，即它多用于字节流传输。
     * 而Filed则相对简单些，通常是字符串键值对。
     *
     * @ [retrofit2.http.Path] 用于url中的占位符,{占位符}和PATH只用在URL的path部分，url中的参数使用Query和QueryMap代替，保证接口定义的简洁 <br></br>
     * @ [retrofit2.http.Query] 用于Get中指定参数 <br></br>
     * @ [retrofit2.http.QueryMap] 和Query使用类似 <br></br>
     * @ [retrofit2.http.Url] 指定请求路径 <br></br>
     */
    fun <T> create(service: Class<T>?): T {
        return getRetrofit().create(service)
    }
}